/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { isEmpty, isString } from 'lodash';
import classnames from 'classnames';
import {
  Button,
  Callout,
  FormGroup,
  Icon,
  InputGroup,
  Intent
} from '@blueprintjs/core';
import PasswordMask from 'react-password-mask';
import { Form, Validation } from 'calidation';

// Actions
import { actionCreators } from '../../../actions';

// Layout
import Empty from '../../Layout/Empty';

// UI
import { Logo } from '../../UI';
import EvaluationPanel from './EvaluationPanel';

// Dialogs
import { EnterLicenseDialog } from '../../Dialogs';

// Utils
import { Settings } from '../../../utils';

// Styles
import './Login.css';

class Login extends Component {
  constructor(props) {
    super(props);

    this.state = {
      username: '',
      password: '',
      isOpenEnterLicenseDialog: false,
      isOpenEvaluationPanel: false,
      isLicenseError: false,
      errors: {}
    };

    this.formValidationConfig = {
      username: {
        isRequired: 'Username field is required'
      },
      password: {
        isRequired: 'Password field is required'
      }
    };
  }

  componentDidMount() {
    const { isAuthenticated } = this.props;

    if (isAuthenticated) {
      this.handleAuthentication();
    }
  }

  componentWillReceiveProps(nextProps) {
    const { isAuthenticated, errors } = nextProps;

    if (isAuthenticated) {
      this.handleAuthentication();
    }

    if (errors) {
      this.setState({ isLicenseError: this.hasLicenseError(errors), errors });
    }
  }

  hasLicenseError(errors) {
    if (!isEmpty(errors) && isString(errors)) {
      return errors.toLowerCase().includes('license');
    }

    return false;
  }

  authenticated() {
    const $el = document.getElementById('sku-progress-indicator');

    $el.removeAttribute('hidden');

    return new Promise(resolve =>
      setTimeout(resolve, Settings.SPLASH_SCREEN_TIME)
    );
  }

  handleAuthentication() {
    const { push } = this.props.history;

    this.authenticated().then(() => push(Settings.DEFAULT_ROUTE));
  }

  handleEnterLicenseDialog = () => {
    this.setState(prevState => ({
      isOpenEnterLicenseDialog: !prevState.isOpenEnterLicenseDialog
    }));
  };

  handleEvaluationPanel = () => {
    this.setState(prevState => ({
      isOpenEvaluationPanel: !prevState.isOpenEvaluationPanel
    }));
  };

  handleSubmit = ({ fields, errors, isValid }) => {
    if (isValid) {
      const { username, password } = fields;

      this.props.doLogin(username, password);
    } else {
      this.setState({ errors: {} });
    }
  };

  handleLoginAs = (username, password) => {
    this.setState({ username, password });
    this.props.doLogin(username, password);
  };

  hideErrorContent = (hide = false) => {
    if (hide) {
      this.setState({ isLicenseError: false, errors: {} });
    }
  };

  renderError() {
    const { isLicenseError, errors } = this.state;

    return (
      <Callout
        className="m-b-20"
        intent={Intent.DANGER}
        style={{ color: '#ee5342' }}
      >
        {errors}
        {isLicenseError && (
          <Button
            className="m-t-10"
            icon="key"
            intent={Intent.DANGER}
            text="Enter License"
            onClick={this.handleEnterLicenseDialog}
            fill
          />
        )}
      </Callout>
    );
  }

  render() {
    const {
      username,
      password,
      isOpenEnterLicenseDialog,
      isOpenEvaluationPanel,
      errors
    } = this.state;
    let showErrorContent;

    if (!isEmpty(errors)) {
      showErrorContent = this.renderError();
    }

    return (
      <Empty>
        <div className="sku-login">
          <div className="sku-logo">
            <Logo width={300} height={150} full />
          </div>
          <Form onSubmit={this.handleSubmit}>
            <Validation config={this.formValidationConfig}>
              {({ fields, errors, submitted, setField }) => (
                <Fragment>
                  {showErrorContent}

                  <FormGroup
                    label="Username"
                    labelFor="username"
                    intent={
                      submitted && errors.username ? Intent.DANGER : Intent.NONE
                    }
                    helperText={
                      submitted && errors.username ? errors.username : ''
                    }
                  >
                    <InputGroup
                      name="username"
                      intent={
                        submitted && errors.username
                          ? Intent.DANGER
                          : Intent.NONE
                      }
                      value={username}
                      onChange={event => {
                        this.setState({ username: event.target.value });
                        setField({ username: event.target.value });
                      }}
                    />
                  </FormGroup>

                  <FormGroup
                    label="Password"
                    labelFor="password"
                    intent={
                      submitted && errors.password ? Intent.DANGER : Intent.NONE
                    }
                    helperText={
                      submitted && errors.password ? errors.password : ''
                    }
                  >
                    <PasswordMask
                      name="password"
                      buttonClassName="btn-password-mask"
                      inputClassName={classnames('bp3-input', {
                        'bp3-intent-danger': submitted && errors.password
                      })}
                      buttonStyles={{ marginTop: '-12px' }}
                      value={password}
                      onChange={event => {
                        this.setState({ password: event.target.value });
                        setField({ password: event.target.value });
                      }}
                    />
                  </FormGroup>

                  <div className="form-group form-group-button">
                    {Settings.EVALUATION_PANEL_LOGIN && (
                      <div className="form-group-button-description">
                        <button
                          type="button"
                          className="link-button"
                          onClick={this.handleEvaluationPanel}
                        >
                          Login as an Evaluator{' '}
                          <Icon
                            icon={
                              isOpenEvaluationPanel
                                ? 'chevron-up'
                                : 'chevron-down'
                            }
                          />
                        </button>
                      </div>
                    )}

                    <Button
                      type="submit"
                      className="button-right"
                      text="Login"
                      intent={Intent.DANGER}
                      loading={this.props.loading}
                      fill={!Settings.EVALUATION_PANEL_LOGIN}
                      large
                    />
                  </div>

                  {Settings.EVALUATION_PANEL_LOGIN && (
                    <EvaluationPanel
                      isOpen={isOpenEvaluationPanel}
                      loginAs={this.handleLoginAs}
                    />
                  )}
                </Fragment>
              )}
            </Validation>
          </Form>
          <div className="sku-login-footer m-b-10">
            <ul>
              <li>Version: {Settings.VERSION}</li>
              <li className="m-r-5 m-l-5">
                <Icon icon="dot" title={false} />
              </li>
              <li>
                <button
                  type="button"
                  className="link-button"
                  onClick={this.handleEnterLicenseDialog}
                >
                  <Icon icon="key" iconSize={14} title={false} /> Enter License
                </button>
              </li>
            </ul>
          </div>
        </div>

        {isOpenEnterLicenseDialog && (
          <EnterLicenseDialog
            hideErrorContent={this.hideErrorContent}
            onClose={this.handleEnterLicenseDialog}
          />
        )}
      </Empty>
    );
  }
}

Login.propTypes = {
  isAuthenticated: PropTypes.bool.isRequired,
  loading: PropTypes.bool.isRequired,
  errors: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
  doLogin: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
  ...state.session,
  errors: state.errors
});

const mapDispatchToProps = dispatch => ({
  doLogin: (username, password) =>
    dispatch(actionCreators.doLogin(username, password))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Login);
